package com.chen.config;

import com.alibaba.fastjson2.JSON;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;

import java.io.IOException;
import java.util.HashMap;

@Configuration
//@EnableWebSecurity //开始 security , springboot项目可以省略
@EnableMethodSecurity  //开启方法授权 ,然后去controller里面确定哪个方法要进行授权
public class WebSecurityConfig {


//  //  只能有一个用户管理器
    //官网给出的配置
//	@Bean
//	public UserDetailsService userDetailsService() {
//		InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
//        //会替换掉.properties里面的配置
//		manager.createUser(User.withDefaultPasswordEncoder().username("cgj").password("666").roles("USER").build());
//		return manager;
//	}


    //    可以在DBUserDetailsManager 类上加上component, 这里就不用写了
//    @Bean
//    public UserDetailsService userDetailsService() {
//        DBUserDetailsManager dbUserDetailsManager = new DBUserDetailsManager();
//        return dbUserDetailsManager;
//    }

    //    官网给出的默认配置 控制过滤器链都有哪些
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(
                        authorize -> authorize
                                //开启方法授权后,这些就都不需要了
                                //用户-权限-资源方式
//                                .requestMatchers("/user/add").hasAuthority("USER_ADD")  //这个权限字符串见名知意就可以
//                                .requestMatchers("/user/list").hasAuthority("USER_LIST")
                                //用户-角色-资源方式
                                //这两种方法都是和用户相关联的
//                                .requestMatchers("/user/**").hasRole("ADMIN")  //角色字符串自己取名字 。 有ADMIN角色的用户可以访问/user下的资源

                                .anyRequest().authenticated()
                ).formLogin(page -> {
                    page.loginPage("/login").permitAll(); //permitAll无需授权就可以访问自己的自定义页面, 防止循环跳转
                }).formLogin(form -> {
//                    form.failureUrl("/login?failure");
                    form.successHandler(new MyAuthenticationSuccessHandler()); //返回登录成功的JSON数据
                    form.failureHandler(new MyAuthenticationFailureHandler()); //登录失败的JSON
                });
        http.logout(logout -> {
            logout.logoutSuccessHandler(new MyLogoutSuccessHandler()); //登出返回json
        });

//                .formLogin(Customizer.withDefaults()); //生成默认的登录登出页面
//                .httpBasic(Customizer.withDefaults());  有上面的表单, 这个也走不到

        // 未登录访问需要权限的接口, 返回JSON
        http.exceptionHandling(exception -> {
            exception.authenticationEntryPoint(new MyAuthenticationEntryPoint());

            //没有授权的接口 (用匿名内部类的方式)
            exception.accessDeniedHandler(new AccessDeniedHandler() {
                @Override
                public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
                    //创建结果对象
                    HashMap result = new HashMap();
                    result.put("code", -1);
                    result.put("message", "没有权限");

                    //转换成json字符串
                    String json = JSON.toJSONString(result);

                    //返回响应
                    response.setContentType("application/json;charset=UTF-8");
                    response.getWriter().println(json);
                }
            });
        });

        //关闭csrf攻击
        http.csrf(csrf -> csrf.disable());


        //允许跨域
        http.cors(cors -> cors.disable());

        //处理session只允许一个用户一个设备登录
        http.sessionManagement(sessionManagement -> {
            sessionManagement.maximumSessions(1).expiredSessionStrategy(new MySessionInformationExpiredStrategy());
        });
        return http.build();
    }
}